#include <unistd.h>

#include <iostream>
#include <thread>
#include <exception>

using namespace std;

void do_something(int &i){
    i++;

    return;
}

/* struct func */
/* { */
/*     int &i; */
/*     func(int &i_): i(i_){} */
/*     void operator()() */
/*     { */
/*         for(unsigned j = 0; j < 100; ++j) */
/*         { */
/*             do_something(i); */
/*         } */
/*     } */
/* }; */

/* int throw_something(){ */
/*     if(true){ */
/*         int i = 1; */
/*         throw i; */
/*     } */

/*     return 1; */
/* } */

//throw int main thread
void f()
{
    int some_local_state = 0;

    thread my_thread(do_something, ref(some_local_state));

    try
    {
        cout << "try to do something" << endl;
        throw 1;
        //throw_something();
    }
    catch(int i)
    {
        cout << "i = " << i << endl;
        cout << "after wait" << endl;
    }
    catch(const char *msg){
        cout << msg << endl;
    }

    my_thread.join();
}

//throw int child thread
//main thread cannot catch other throw exception
/* void throwThread(){ */
/*     throw 1; */

/*     return; */
/* } */

/* void g(){ */
/*     try{ */
/*         thread my_thread(throwThread); */
/*     } */
/*     catch(int i) */
/*     { */
/*         cout << "catch i = " << i << endl; */
/*     } */

/*     cout << "successfully" << endl; */

/*     return; */
/* } */

//throw in child thread
//use exception_ptr to save child thread exception
//rethrow_exception in main thread to catch
exception_ptr eptr = nullptr;

void willThrow(){
    cout << "child thread throw a exception_ptr" << endl;
    try
    {
        //throw 1;
        string().at(1);
    }
    catch(...)
    {
        eptr = current_exception();
        cout << "catch the exception" << endl;
    }
}

void h(){
    thread my_thread(willThrow);

    my_thread.join();
    try
    {
        if(eptr){
            cout << "rethrow_exception" << endl;
            rethrow_exception(eptr);
        }
    }
    catch(const exception & e)
    {
        cout << "the exception is " << e.what() << endl;
    }
    /* catch(const char *msg) */
    /* { */
    /*     cout << msg <<endl; */
    /* } */

    cout << "success" << endl;
    return;
}

int main()
{
    /* f(); */
    /* g(); */
    h();
    return 0;
}

